WhaleCTF 密码学wp

0x00 前言

这段时间把whaleCTF的密码学部分进行了收尾,完成了部分题目,仍剩下一题亟待解决.

0x01 解题记录

Death_Chain 100

题目: 某天,夏多抛出了一张纸条.满是圆圈的纸条应该有所隐藏信息,你能够发现吗?
答案格式: flag{xxxx},xxx是所有的解密内容,大写

知识点: 夏多密码

解题记录: 根据提示搜索“夏多密码”,可以得到如图所示的密码表.

Death_Chain.png-28.2kB

把所给的密文与密码表进行对照,可以得到flag.

先有什么 100

题目: 这是个值得思考的问题,到底先有什么——UFO?麦田怪圈?答案格式: key{flag},flag是解密内容.

知识点: 键盘密码

解题记录: 键盘密码,将所给的字母在键盘上连起来,找到每一部分中间所包围的字母即可.

检查符号 100

题目: 截取一段电波,一不小心全变成了泡泡.你能够解密吗? “o00。o。o0oo。0o0o。000。00。o。0。000。ooo0。o。0o。oo0。ooo。0o0o。0。oo0o” 答案格式: key{flag},flag是解密内容.

知识点: 摩斯电码

解题记录: 打开txt文件发现有数字0,句号和字母o构成,猜想是摩斯电码.写一个脚本解密.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
def mouse(a):
result = ''
dict = {'.-':'A',
'-...':'B',
'-.-.':'C',
'-..':'D',
'.':'E',
'..-.':'F',
'--.':'G',
'....':'H',
'..':'I',
'.---':'J',
'-.-':'K',
'.-..':'L',
'--':'M',
'-.':'N',
'---':'O',
'.--.':'P',
'--.-':'Q',
'.-.':'R',
'...':'S',
'-':'T',
'..-':'U',
'...-':'V',
'.--':'W',
'-..-':'X',
'-.--':'Y',
'--..':'Z',
'-----':'0',
'.----':'1',
'..---':'2',
'...--':'3',
'....-':'4',
'.....':'5',
'-....':'6',
'--...':'7',
'---..':'8',
'----.':'9',
'.-.-.-':'.',
'---...':':',
'--..--':',',
'-.-.-.':';',
'..--..':'?',
'-...-':'=',
'.----.':'\'',
'-..-.':'/',
'-.-.--':'!',
'-....-':'-',
'..--.-':'_',
'.-..-.':'"',
'-.--.':'(',
'-.--.-':')',
'...-..-':'$',
'....':'&',
'.--.-.':'@'
}
for item in a:
if item in dict:
result += dict[item]
else:
return None
return result

if __name__ == '__main__':
#重点使用replce()方法和split()方法,前者用于替换字符串中的字符,后者用于切割字符串
str1 = 'o00。o。o0oo。0o0o。000。00。o。0。000。ooo0。o。0o。oo0。ooo。0o0o。0。oo0o'
str2 = str1.replace('。',' ')
str3 = str2.replace('o','.')
str4 = str3.replace('0','-')
L1 = str4.split(' ')
result_1 = mouse(L1)
if result_1 == None:
str3 = str2.replace('o','-')
str4 = str3.replace('0','.')
L2 = str4.split(' ')
result_2 = mouse(L2)
print result_2
else:
print result_1

德军密码 100

题目: 二战时盟军截获德军一段密码,密文为: 000001100000000010101011011100101
1000101100000111001100100111100111001(密钥: helloworld),你可能会解出一个keyxxxxx的答案,请在y后面加{,结尾加},答案的格式是key{xxxxx},所以答案是

知识点: 费纳姆密码

解题记录: 打开题目后发现key以及一长串二进制数字,结合所给提示德军密码,可知是费纳姆编码,写个脚本跑一下.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
transform1 = {'1000001':'A','1000010':'B',
'1000011':'C','1000100':'D',
'1000101':'E','1000110':'F',
'1000111':'G','1001000':'H',
'1001001':'I','1001010':'J',
'1001011':'K','1001100':'L',
'1001101':'M','1001110':'N',
'1001111':'O','1010000':'P',
'1010001':'Q','1010010':'R',
'1010011':'S','1010100':'T',
'1010101':'U','1010110':'V',
'1010111':'W','1011000':'X',
'1011001':'Y','1011010':'Z'}

#反转字典,方便将key进行编码
transform2 = {value:key for key,value in transform1.items()}

cipher = '0000011000000000101010110111001011000101100000111001100100111100111001'

key = 'helloworld'
#将字母转换成01字符串
def trans1(key):
list2 = []
for item in key.upper():
list2.append(transform2[item])
return list2
#将01字符串分割
def trans2(cipher):
num = 0
result = []
plain = ''
while True:
result.append(cipher[num:num+7])
num += 7
if(num > len(cipher)-7):
break
return result
#自定义异或操作
def XOR(text,keynew):
result = ''
for i in range(0,len(text)):
if text[i] == keynew[i]:
result += '0'
else :
result += '1'
return result


if __name__ == '__main__':
key1 = trans1(key)
cipher1 = trans2(cipher)
key2 = ''.join(key1)
cipher2 = ''.join(cipher1)
result = XOR(key2,cipher2)
result1 = trans2(result)
result2 =''
for i in result1:
if i not in transform1:
result2 += ' '
else:
result2 += transform1[i]
print result2

这里介绍几个知识点:

  • 构建字母转换成二进制的字典的时候,不需要重新构建,只需要将原来字典的key和value互换位置.

transform2 = {value:key for key,value in transform1.items()}

  • 01字符串分组处理时,可以使用索引加7的方法进行处理.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def trans2(cipher):
    num = 0
    result = []
    plain = ''
    while True:
    result.append(cipher[num:num+7])
    num += 7
    if(num > len(cipher)-7):
    break
    return result

注意最后得到的数组中有字典中没有的key,我们使用空格来进行代替,最后将空格手动替换成花括号即可.

密钥生成 100

题目: 在一次RSA密钥对生成中,假设p=473398607161,q=4511491,e=17求解出d,格式: key{xxxx}

知识点: rsa中d的生成

解题记录: 已知p,q,e,使用模反求d的方法求出来d即可.

规则很公平 150

题目: vv公司称,他们给出了最为公平的游戏规则,你能猜到是什么吗?规则: CGOCPMOFEBMLUNISEOZY,附件: CULTREABDFGHIKMNOPQSVWXYZ. 答案的格式是key{xxxxx},所以答案是.

知识点: 波雷菲尔密码

解题记录: 由“公平”联想到英文“fair”,从而联想到playfair密码.我们使用造好的轮子即pycipher库中的Playfair函数来进行操作.

1
2
from pycipher import Playfair
Playfair('CULTREABDFGHIKMNOPQSVWXYZ').decipher('CGOCPMOFEBMLUNISEOZY')

将得到的结果进行适当删减即可获得flag.

数学小问题 150

题目: 小小的数学问题,你能搞定吗?SElWTVVSQ1FXUUlXVUhFVg, 答案的格式是key{xxxxx},所以答案是

知识点: base64+仿射密码

解题记录: 首先根据图片提示得知为仿射密码,先写了一个脚本,但跑出来发现结果没有有意义的明文,便卡了一段时间.

后来仔细观察密文,发现类似base64的形式,遂在其后加上==进行base解密,将得到的密文再跑仿射脚本,可以得到有意义的结果.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import base64
cipher = 'SElWTVVSQ1FXUUlXVUhFVg=='
plain1 = base64.b64decode(cipher)

#只有a与26互素,a模26的逆元才存在,才可以进行解密
dict = [1,3,5,7,9,11,15,17,19,21,23,25]

plain2 = plain1.lower()

for a in dict:
for b in range(26):
plain3 = ''
for item in plain2:
plain3 += chr((a*(ord(item)-97)+b)%26+97)
print plain3

此处应写 150

记录一下该问题的复杂版,即CTF-30days的填空题.

题目: 拿到一个填空题,到底该填什么?答案的格式是key{xxxxx},所以答案是

知识点: utf-9编码+字符匹配
该题目下载得到的文件名为: flag is here rfc4042,无法通过文本编辑等打开.百度查找rfc4042,发现该文件可能使用了utf-9编码.

解题记录: 写一个脚本进行译码.

1
2
3
4
5
6
import utf9
f = open('flag_is_here_rfc4042','rb')
result = ''
for line in f:
result += line
print utf9.utf9decode(result)

将得到的结果中的下划线数量转换成数字,其他符号不变.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
cipher = '_____*((__//__+___+______-____%____)**((___%(___-_))+________+(___%___+_____+_______%__+______-(______//(_____%___)))))+__*(((________/__)+___%__+_______-(________//____))**(_*(_____+_____)+_______+_________%___))+________*(((_________//__+________%__)+(_______-_))**((___+_______)+_________-(______//__)))+_______*((___+_________-(______//___-_______%__%_))**(_____+_____+_____))+__*(__+_________-(___//___-_________%_____%__))**(_________-____+_______)+(___+_______)**(________%___%__+_____+______)+(_____-__)*((____//____-_____%____%_)+_________)**(_____-(_______//_______+_________%___)+______)+(_____+(_________%_______)*__+_)**_________+_______*(((_________%_______)*__+_______-(________//________))**_______)+(________/__)*(((____-_+_______)*(______+____))**___)+___*((__+_________-_)**_____)+___*(((___+_______-______/___+__-_________%_____%__)*(___-_+________/__+_________%_____))**__)+(_//_)*(((________%___%__+_____+_____)%______)+_______-_)**___+_____*((______/(_____%___))+_______)*((_________%_______)*__+_____+_)+___//___+_________+_________/___'

m = cipher[0]
count = 0
plain = ''

for i in cipher:
if i is m:
count += 1 #将短线化成数字1并加到count变量
else:
if count != 0:
plain += str(count) #当碰到运算符号的时候,先将前面累计的count化成数字
count = 0
plain += i #再将运算符号放入算式
else:
plain += i #前面没有累计的count,直接将运算符号放入算式
if count != 0:
plain += str(count) #将表达式最后的短线代表的数字放入算式

print plain
result = eval(plain)
print result

将运算后的结果转换成十六进制然后两个一组转换成字符即可.

1
2
3
4
5
6
key = 5287002131074331513
cipher = hex(key)[2:]
plain = ''
for i in range(len(cipher) / 2):
plain += chr(int(cipher[i * 2 : i * 2 + 2], 16))
print plain

栅栏加密 150

题目: 我家篱笆旁的栅栏被捣乱了!第一根和第二根都被换了位置…只有第三根还能站在那,缺也短了一截了.变成了这样: udJZml2VYVuWkdxXXs2Ne1DV5V9XEs2ZdZ7WlSNbVrm9eNDSlaFXG91F谁能帮我修好呢?flag格式: venusCTF{xxx}

知识点: 栅栏密码

解题记录: 按照要求写出来即可.

栅栏加密.png-78.4kB

小明入侵 150

题目: 小明入侵网站后获得了管理员的密文,由于太高兴了手一抖把密文删除了一部分,只剩下前10位a74be8e20b,小明根据社工知道管理员的密码习惯是key{4位的数字或字母},所以管理员的密码是.

知识点: md5解密

解题记录: 查找可知一般的网站管理员的登录密文是经过md5和sha1加密,因为只有四位,故可以使用脚本进行解题.注意构造的字典需要包含大小写字母和数字.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import hashlib
dict = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']

def cal(a):
t = hashlib.md5()
t.update(str(a).encode('ascii'))
encodestr = t.hexdigest()
return encodestr

if __name__ == '__main__':
a=''
for i in dict:
for j in dict:
for k in dict:
for l in dict:
a = 'key{'+ str(i)+str(j)+str(k)+str(l)+'}'
result = cal(str(a))
if result[0:10] == 'a74be8e20b':
print a
print result
else:
pass

RSA破解 200

题目: 得到了公钥,怎么才能解密呢?
tip分解n,答案格式ISG{flag}

知识点: openssl的使用,n的分解

解题记录: 打开解压后的文件,发现证书和加密后的文件.使用openssl提取n.

1
openssl rsa -pubin -text -modulus -in warmup -in pem证书的路径

得到下图所示的n.

rsa1.png-114.4kB

得到的n显然是十六进制,所以将其转换成十进制,尽量不要使用在线进制转换.随后使用在线网站(在线大数分解)进行解密,得到p和q,然后使用rsatool.py脚本及openssl配合(同一目录)得到flag.

1
python rsatool.py -o private.pem -e e的值 -p p的值 -q q的值

得到私钥之后使用openssl进行解密.

1
openssl rsautl -decrypt -in flag.enc -inkey private.pem -out flag.txt

RSA分解 200

题目: 某安全公司通过网络监听截取了某间谍连续发送的一段明文和公钥,你能够解密传输内容吗?

知识点: rsa已知密文和公钥进行解密

解题记录: 已知n和e公钥对,首先将n进行分解,再求出来d,使用解密脚本解密即可.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
p = 18443
q = 49891
e = 19
d = 96849619
n = 920139713
m =[
704796792,
752211152,
274704164,
18414022,
368270835,
483295235,
263072905,
459788476,
483295235,
459788476,
663551792,
475206804,
459788476,
428313374,
475206804,
459788476,
425392137,
704796792,
458265677,
341524652,
483295235,
534149509,
425392137,
428313374,
425392137,
341524652,
458265677,
263072905,
483295235,
828509797,
341524652,
425392137,
475206804,
428313374,
483295235,
475206804,
459788476,
306220148
]

for i in range(len(m)):
print pow(m[i],d,n)

将得到的结果进行ascii转码,得到字符串.

只有密文 200

题目: 怎么办,已经截获了密文和模数n!能够破解吗?请分解出RSA中的两个大素数q和p.提交格式是key{x}x为两个素数中较小的那个的MD5前8位.

知识点: 唯密文攻击.

rsa中只提供密文和n的时候,可以先求出来每一组密文和n的最大公约数,找出来非1的公约数,该数字即为p或者q,再结合n求出来p或q,即可还原整个加密过程.

解题记录: 根据唯密文攻击的原理,编辑脚本进行计算.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import hashlib
#cipher为所给密文构成的数组

def gcd(a,b):
tmp = 1
while(tmp != 0):
tmp = a%b
a = b
b = tmp
return a

def hash(m):
t = hashlib.md5()
t.update(str(m).encode('ascii'))
result = t.hexdigest()
return result[0:9]

if __name__ == '__main__':
result = ''
for i in range(len(cipher)):
if gcd(n,cipher[i]) != 1:
print ('The common divisor of n and ' + 'cipher ' +str(i+1) + ' = ' + str(gcd(n ,cipher[i])))
break
p = gcd(n,cipher[i])
q = n/p
t = hashlib.md5()
if p > q:
result = hash(q)
else:
result = hash(p)
print result

RSA专家

题目: 得到了私钥,破解还不简单吗?
格式: key{xxx}

知识点: openssl的使用

解题记录: zip解压的到aaaa和endata,直接openssl解密.

1
openssl rsautl -decrypt -in endata -inkey aaaa -out flag.txt

0x03 others

whale的密码题还有一道”大家来解密”没有完成,给出了key和iv猜想是aes系列.”算法问题”的flag就在所给脚本中,没有什么价值.

请作者吃个小鱼饼干吧